﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace SharedLib.Helpers
{
    /// <summary>
    /// If there are multiple threads accesing the calculation logic at the same time, the logic will be executed only once.
    /// The callers will get the result once the first calculation got completed.
    /// </summary>
    public class CalculateOnce<TResult>
    {
        int _gateFlag = 0;
        Func<TResult> _func;
        TResult _result;
        ManualResetEvent _mre = new ManualResetEvent(false);
        public TResult Result
        {
            get {
                _mre.WaitOne();
                return _result; 
            }
            private set { _result = value; }
        }
        public CalculateOnce(Func<TResult> action)
        {
            _func = action;
        }

        public void Execute()
        {
            if (Interlocked.Increment(ref _gateFlag) == 1)
            {
                //Only execute the first caller
                Result = _func.Invoke();
                _mre.Set();
            }
            Interlocked.Decrement(ref _gateFlag);
        }
    }
}
